import sys
sys.path.append('/mnt/labshare/Programs/python/HelperFunctions/')
from os import path, listdir
from scipy.constants import c, epsilon_0, mu_0
from scipy.special import ellipk, ellipkm1
from numpy import *
from IPython.display import Image
%pylab inline
pylab.rcParams['figure.figsize'] = (12, 9)
pylab.rcParams['font.size'] = 22
from scipy.constants import epsilon_0, h, hbar, e, pi
from scipy.special import ellipk
import plotly.plotly as py
from plotly.tools import mpl_to_plotly
from plotly.offline import init_notebook_mode, iplot_mpl, iplot
from plotlylayouts import *
init_notebook_mode()
import pandas as pd
import re
from os import path, listdir
simdatapath = '/mnt/labshare/Chip Design/JPMQubitV3/Q3D Simulations'
listdir(simdatapath)
e0 = 1
e1 = 11.6
class cpw:
def __init__(self, w=10., s=6., t=.1, h=500., l=1000., e1=11.6, material="nb", tgdelta=1e-8):
self.w = w*1e-6
self.s = s*1e-6
self.t = t*1e-6
self.h = h*1e-6
self.l = l*1e-6
self.e1 = e1
self.tgdelta = tgdelta
self.material = material
if material == "al":
self.Tc = 1.23
self.rho = 4e-9
elif material == 'nb':
self.Tc = 8
self.rho = 4e-9
self.l0 = 1.05e-3*sqrt(self.rho/self.Tc)
# Effective Dielectric Constant from Silicon-Air Interface
def k0(self):
return self.w/(self.w+2*self.s)
def kp0(self):
return sqrt(1-self.k0()**2)
def k1(self):
return sinh(pi*self.w/(4*self.h))/sinh(pi*(2*self.s+self.w)/(4*self.h))
def kp1(self):
return sqrt(1-self.k1()**2)
def Eeff(self):
return 1 + ((self.e1-1)*ellipk(self.k1())*ellipk(self.kp0()))/(2*ellipk(self.kp1())*ellipk(self.k0()))
# Kinetic Inductance Calculation
def g(self):
a = -log(self.t/(4*self.w))
b = -self.w/(self.w+2*self.s)*log(self.t/(4*(self.w+2*self.s)))
c = 2*(self.w+self.s)/(self.w+2*self.s)*log(self.s/(self.w+self.s))
return 1/(1*self.k0()**2*ellipk(self.k0())**2) * (a+b+c)
def Llk(self):
return mu_0*self.l0**2/(self.w*self.t)*self.g()
# Circuit Parameters
def Ll(self):
return mu_0*ellipk(self.kp0())/(4*ellipk(self.k0())) + self.Llk()
def Cl(self):
return 4*epsilon_0*self.Eeff()*ellipk(self.k0())/ellipk(self.kp0())
def vph(self):
return 1/sqrt(self.Ll()*self.Cl())
def f0(self):
return c/(sqrt(self.Eeff())*2*self.l)
def z0(self):
return sqrt(self.Ll()/self.Cl())
# Loss
def k(self):
return 2*pi*self.f0()*sqrt(self.Eeff())/c
def alpha_d(self):
return self.e1/sqrt(self.Eeff())*(self.Eeff()-1)/(self.e1-1)*self.tgdelta*self.k()/2
# Circuit Parameters with Loss
def L(self):
return 2*self.Ll()*self.l/(pi**2)
def C(self):
return self.Cl()*self.l/2
def R(self):
return self.z0()/(self.alpha_d()*self.l)
def Qint(self):
return self.R()*self.C()/sqrt(self.L()*self.C())
def wn(self):
return self.Qint()/(self.R()*self.C())
def fn(self):
return self.wn()/(2*pi)
class resonator:
def __init__(self, cpw, cin, cout):
self.cpw = cpw
self.cki = cin
self.cko = cout
def Rin(self):
# Effective input resistance to ground
return (1. + (self.cpw.wn()*self.cki*50.)**2)/(self.cpw.wn()*self.cki*50.)**2
def Rout(self):
# Effective output resistance to ground
return (1. + (self.cpw.wn()*self.cko*50.)**2)/(self.cpw.wn()*self.cko*50.)**2
def Cin(self):
# Effective input capacitance to ground
return self.cki/(1. + (self.cpw.wn()*self.cki*50.)**2)
def Cout(self):
# Effective output capacitance to ground
return self.cko/(1. + (self.cpw.wn()*self.cko*50.)**2)
def wl(self):
# Loaded frequency in rad/s
return 1./sqrt(self.cpw.L()*(self.cpw.C() + self.Cin() + self.Cout()))
def fl(self):
# Loaded frequency in GHz
return self.wl()/2/pi/1e9
def Qc(self):
# Total coupling Q
return self.cpw.wn() * (self.cpw.C() + self.Cin() + self.Cout())/(1./self.cpw.R() + 1./self.Rin() + 1./self.Rout())
def Ql(self):
# Loaded Q
return 1/(1/self.cpw.Qint() + 1/self.Qc())
def kappa(self):
# Photon loss rate
return self.wl()/self.Ql()
def __str__(self):
return "l = {} um\nf = {} GHz\nQ = {}\nk = {} MHz".format(self.cpw.l*1e6,self.fl(), self.Ql(), self.kappa()/2e6/pi)
Here we investigate using coplanar capacitors with a continuous ground plane in between.
Image('Coupling Cap.png')
In the following analysis, $xt$ represents the thickness of the capacitor electrodes, and $yt$ represents the length/overlap of the electrodes.
Simulating the above capacitor in Q3D, we get the following results.
This is with a 2$\mu m$ ground plane in between the electrodes.
df = pd.read_csv(path.join(simdatapath, '2D Capacitive Coupling.csv'))
strip = lambda x: float(x[:-2])
for i, col in enumerate(df.keys()):
if re.search('[a-zA-Z]+', str(df[col][0])):
unit = re.findall("[a-zA-Z]+", df[col][0])[0]
print("Column {} has units {}, Stripping...".format(i, unit))
df[col] = df[col].apply(strip)
df.rename(columns={col: col + ":" + unit}, inplace=True)
layout, trace = HeatmapPlot(title="Resonator Capacitance (fF)")
trace['x'] = df['xt:um'];layout['xaxis']['title'] = "xt (um)"
trace['y'] = df['yt:um'];layout['yaxis']['title'] = "yt (um)"
trace['z'] = df['Cr: Freq(1GHz): Original:pF']*1e3
iplot(Figure(data=[trace], layout=layout))
Here we look at the resonator quality vs. input and output coupling capacitors.
An $R_l=50\Omega$ load coupled to a cavity with capacitance $C_k$ can be modelled as an effective capacitance $C^*$ and resistance $R^*$ to ground using the following equations:
$$ C^* = \frac{C_k}{1 + \omega_n^2C_k^2R_l^2} $$$$ R^* = \frac{1+\omega_n^2C_k^2R_l^2}{\omega_n^2C_k^2R_l} $$For an asymmetric coupling ($C_i \neq C_o$), the coupling $Q_c$ and loaded frequency $\omega_n^*$ are given by
$$ Q_c = \omega_n^*\frac{C + C_i^* + C_o^*}{1/R + 1/R_i^* + 1/R_o^*} $$$$ \omega_n^* = \frac{1}{\sqrt{L_n(C + C_i^* + C_o^*)}} $$## Example of loading effect
l = 11840. #um
line = cpw(l=l)
print("Length: {} um".format(l))
print("Unloaded Frequency: {} GHz".format(line.fn()/1e9))
cin = 5e-15 #F
cout= 5e-15 #F
res = resonator(line, cin, cout)
print("Coupling quality factor: {}".format(res.Qc()))
print("Loaded Q: {}".format(res.Ql()))
print("Loaded frequency: {} GHZ".format(res.fl()))
print(res)
Cout = linspace(1, 20, 101)*1e-15 # F
l = 11840 #um
line = cpw(l=l) #CPW Length
cin = 1e-15 # F
kappas = []
freqs = []
for cout in Cout:
kappas.append(resonator(line, cin, cout).kappa()/2e6/pi) #Find kappa in MHz
freqs.append(resonator(line, cin, cout).fl())
layout, trace = LinePlot(title="Linewidth vs. output capacitance", x=Cout*1e15, y=kappas)
layout['xaxis'].update(title='Output Capacitance (fF)')
layout['yaxis'].update(title='Kappa (MHz)')
iplot(Figure(data=[trace], layout=layout))
layout, trace = LinePlot(title="Frequency vs. output capacitance", x=Cout*1e15, y=freqs)
layout['xaxis'].update(title='Output Capacitance (fF)')
layout['yaxis'].update(title='Resonant Frequency (GHz)')
iplot(Figure(data=[trace], layout=layout))